package cn.mesmile.thread.jvm;

import java.io.FileInputStream;
import java.lang.reflect.Method;

/**
 * @author zb
 * @date 2021/4/1 22:19
 * @Description:
 */
public class MyClassLoaderTest {

    static class MyClassLoader extends ClassLoader {

        private String classPath;

        public MyClassLoader(String classPath){
            this.classPath = classPath;
        }

        private byte[] loadByte (String name) throws Exception {
            name = name.replaceAll("\\." , "/");
            FileInputStream fileInputStream = new FileInputStream(classPath + "/" + name + ".class");
            int available = fileInputStream.available();
            byte[] data = new byte[available];
            fileInputStream.read(data);
            fileInputStream.close();
            return data;
        }

        // findClass() 加载类
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] data = loadByte(name);
                // defineClass 将一个字节数组转为Class对象，这个字节数组是class文件读取后最终的字节数组
                System.out.println("name = " + name);
                return defineClass(name, data, 0, data.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }

        }


        /**
         *  打破双亲委派机制
         *
         */
        @Override
        protected Class<?> loadClass(String name, boolean resolve)
                throws ClassNotFoundException
        {
            synchronized (getClassLoadingLock(name)) {
                // First, check if the class has already been loaded
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    long t0 = System.nanoTime();
//                    try {
//                        if (parent != null) {
//                            c = parent.loadClass(name, false);
//                        } else {
//                            c = findBootstrapClassOrNull(name);
//                        }
//                    } catch (ClassNotFoundException e) {
//                        // ClassNotFoundException thrown if class not found
//                        // from the non-null parent class loader
//                    }
//
//                    if (c == null) {
                        // If still not found, then invoke findClass in order
                        // to find the class.
                    // 当类的名称是非 cn.mesmile 的时候，就采用双亲委派机制
                    if(!name.startsWith("cn.mesmile")){
                        c = this.getParent().loadClass(name);
                    } else {

                        long t1 = System.nanoTime();
                        c = findClass(name);

                        // this is the defining class loader; record the stats
                        sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                        sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                        sun.misc.PerfCounter.getFindClasses().increment();
                    }

//                    }
                }
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
        }
    }

    public static void main(String[] args) throws Exception {
        // 指定类加载器的路径
        MyClassLoader myClassLoader = new MyClassLoader("D:/test");
        // 加载指定的类  D 盘创建 test/cn/mesmile/thread/jvm  【双亲委派机制】 loadClass() ---》  findClass() 加载类
        Class<?> aClass = myClassLoader.loadClass("cn.mesmile.thread.jvm.Student");

        // 反射调用方法
        Object o = aClass.newInstance();
        Method sout = aClass.getDeclaredMethod("sout", null);
        sout.invoke(o, null);

        System.out.println(aClass.getClassLoader().getClass().getName());


        // 模拟Tomcat 打破双亲委派机制
        System.out.println(">>>>>>>>>>>另外一个类>>>>>>>>>");
        // 指定类加载器的路径
        MyClassLoader myClassLoader2 = new MyClassLoader("D:/test1");
        // 加载指定的类  D 盘创建 test/cn/mesmile/thread/jvm  【双亲委派机制】 loadClass() ---》  findClass() 加载类
        Class<?> aClass2 = myClassLoader2.loadClass("cn.mesmile.thread.jvm.Student");

        // 反射调用方法
        Object o2 = aClass2.newInstance();
        Method sout2 = aClass2.getDeclaredMethod("sout", null);
        sout2.invoke(o2, null);

        System.out.println(aClass2.getClassLoader().getClass().getName());
    }

}
